//
//  ViewController.m
//  GCDBenchmark
//
//  Created by 郭晓龙 on 2025/10/9.
//

#import "ViewController.h"
#import "BenchmarkConfig.h"
#import "BenchmarkTestCase.h"
#import "BenchmarkTestCell.h"
#import "BenchmarkTestConfigViewController.h"
#import "TestResultViewController.h"
#import "RunAllResultsViewController.h"
#include <cmath>
#include "basic_case.h"
#include "playback.h"
#include "auto_test.h"

// Global variable from AppDelegate
extern NSString *g_autoTestCase;

static NSInteger IntegerParam(NSDictionary<NSString *, id> *params, NSString *key, NSInteger defaultValue) {
    NSNumber *number = params[key];
    if ([number respondsToSelector:@selector(integerValue)]) {
        return number.integerValue;
    }
    return defaultValue;
}

static NSString *DisplayTaskType(NSInteger taskType) {
    switch (taskType) {
        case 0: return @"CPU";
        case 1: return @"IO";
        case 2: return @"Suspend";
        default: return [NSString stringWithFormat:@"类型%ld", (long)taskType];
    }
}

static NSString *DisplayQoS(qos_class_t qos) {
    switch (qos) {
        case QOS_CLASS_DEFAULT: return @"Default";
        case QOS_CLASS_USER_INITIATED: return @"UserInitiated";
        case QOS_CLASS_USER_INTERACTIVE: return @"UserInteractive";
        case QOS_CLASS_UTILITY: return @"Utility";
        case QOS_CLASS_BACKGROUND: return @"Background";
        case QOS_CLASS_UNSPECIFIED: return @"Unspecified";
        default: return [NSString stringWithFormat:@"QoS(%d)", (int)qos];
    }
}

static NSString *FormatMicrosecondsValue(NSInteger microseconds) {
    if (microseconds >= 1000) {
        double ms = microseconds / 1000.0;
        return [NSString stringWithFormat:@"%.2fms", ms];
    }
    return [NSString stringWithFormat:@"%ldus", (long)microseconds];
}

@interface ViewController () <UITableViewDelegate, UITableViewDataSource, BenchmarkTestCellDelegate>

@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UILabel *resultLabel;
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator;

@property (nonatomic, strong) NSArray<BenchmarkTestCase *> *testCases;
@property (nonatomic, strong) BenchmarkConfig *config;
@property (nonatomic, strong) TestResultViewController *resultVC;
@property (nonatomic, strong) UIBarButtonItem *runAllButton;
@property (nonatomic, strong) UISwitch *autoExitSwitch;
@property (nonatomic, strong) UIBarButtonItem *autoExitSwitchItem;
@property (nonatomic, assign) BOOL isRunningAllTests;
@property (nonatomic, assign) NSInteger currentRunAllIndex;
@property (nonatomic, copy) NSArray<BenchmarkTestCase *> *runAllQueue;
@property (nonatomic, strong) RunAllResultsViewController *runAllResultsVC;
@property (nonatomic, strong, nullable) dispatch_source_t countdownTimer;
@property (nonatomic, assign) NSInteger countdownSecondsRemaining;
@property (nonatomic, assign) BOOL pendingAutoExitAfterRunAll;
@property (nonatomic, assign) BOOL playbackTestsSkipped;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Check if running in auto-test mode (test case name set in AppDelegate)
    if (g_autoTestCase != nil) {
        return;  // Don't setup UI
    }

    // 加载配置
    self.config = [BenchmarkConfig sharedConfig];
    // 初始化测试用例
    [self setupTestCases];

    // 设置UI
    [self setupUI];
}

- (void)setupTestCases {
    self.testCases = @[
        [[BenchmarkTestCase alloc] initWithType:BenchmarkTestCaseTypeForkJoin
                                           name:@"Fork-Join 模式"
                                           icon:@"🔱"],
        [[BenchmarkTestCase alloc] initWithType:BenchmarkTestCaseTypeFibonacci
                                           name:@"斐波那契递归"
                                           icon:@"🌀"],
        [[BenchmarkTestCase alloc] initWithType:BenchmarkTestCaseTypeAriawNSOperation
                                           name:@"ARIAW NSOperation"
                                           icon:@"🔄"],
        [[BenchmarkTestCase alloc] initWithType:BenchmarkTestCaseTypeAriawSemaphore
                                           name:@"ARIAW Semaphore"
                                           icon:@"🚦"],
        [[BenchmarkTestCase alloc] initWithType:BenchmarkTestCaseTypeSerialQueue
                                           name:@"串行队列"
                                           icon:@"➡️"],
        [[BenchmarkTestCase alloc] initWithType:BenchmarkTestCaseTypeConcurrentQueue
                                           name:@"并发队列"
                                           icon:@"⚡️"],
        [[BenchmarkTestCase alloc] initWithType:BenchmarkTestCaseTypePeriodicTasks
                                           name:@"周期性任务"
                                           icon:@"⏱"],
        [[BenchmarkTestCase alloc] initWithType:BenchmarkTestCaseTypePlayback
                                           name:@"Playback 测试"
                                           icon:@"📹"],
    ];
}

- (NSArray<NSString *> *)playbackFileNames {
    NSArray<NSString *> *paths = [[NSBundle mainBundle] pathsForResourcesOfType:@"playback" inDirectory:nil];
    NSMutableArray<NSString *> *fileNames = [NSMutableArray arrayWithCapacity:paths.count];
    for (NSString *path in paths) {
        NSString *name = path.lastPathComponent;
        if (name.length > 0) {
            [fileNames addObject:name];
        }
    }
    return [fileNames copy];
}

- (NSString *)displayNameForTestCase:(BenchmarkTestCase *)testCase {
    if (testCase.type == BenchmarkTestCaseTypePlayback) {
        NSString *fileName = testCase.customParams[kParamSelectedFileName];
        if (fileName.length > 0) {
            return [NSString stringWithFormat:@"%@ - %@", testCase.name, fileName];
        }
    }
    return testCase.name;
}

- (void)setupUI {
    self.view.backgroundColor = [UIColor systemBackgroundColor];
    self.title = @"GCD Benchmark";

    // 导航栏 - 全部执行 & 自动退出开关
    self.runAllButton = [[UIBarButtonItem alloc] initWithTitle:@"全部执行"
                                                         style:UIBarButtonItemStylePlain
                                                        target:self
                                                        action:@selector(runAllTestsTapped)];
    self.navigationItem.rightBarButtonItem = self.runAllButton;

    UILabel *autoExitLabel = [[UILabel alloc] init];
    autoExitLabel.text = @"自动退出";
    autoExitLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];

    self.autoExitSwitch = [[UISwitch alloc] init];
    self.autoExitSwitch.on = self.config.autoExitEnabled;
    [self.autoExitSwitch addTarget:self action:@selector(autoExitSwitchChanged:) forControlEvents:UIControlEventValueChanged];

    UIStackView *switchStack = [[UIStackView alloc] initWithArrangedSubviews:@[autoExitLabel, self.autoExitSwitch]];
    switchStack.axis = UILayoutConstraintAxisHorizontal;
    switchStack.spacing = 6;
    switchStack.alignment = UIStackViewAlignmentCenter;

    self.autoExitSwitchItem = [[UIBarButtonItem alloc] initWithCustomView:switchStack];
    self.navigationItem.leftBarButtonItem = self.autoExitSwitchItem;

    // 创建列表
    self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    self.tableView.estimatedRowHeight = 72;
    [self.tableView registerClass:[BenchmarkTestCell class] forCellReuseIdentifier:@"TestCell"];
    [self.view addSubview:self.tableView];

    // 结果显示标签（作为TableView的footer）
    self.resultLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 100)];
    self.resultLabel.text = @"👆 选择测试用例开始";
    self.resultLabel.textAlignment = NSTextAlignmentCenter;
    self.resultLabel.numberOfLines = 0;
    self.resultLabel.font = [UIFont systemFontOfSize:14];
    self.resultLabel.textColor = [UIColor secondaryLabelColor];

    UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 120)];

    self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
    self.activityIndicator.hidesWhenStopped = YES;
    self.activityIndicator.center = CGPointMake(footerView.bounds.size.width / 2, 20);
    [footerView addSubview:self.activityIndicator];

    self.resultLabel.frame = CGRectMake(20, 40, footerView.bounds.size.width - 40, 80);
    [footerView addSubview:self.resultLabel];

    self.tableView.tableFooterView = footerView;

    // 设置约束
    [NSLayoutConstraint activateConstraints:@[
        [self.tableView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
        [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
        [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
        [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
    ]];
}

- (void)autoExitSwitchChanged:(UISwitch *)sender {
    self.config.autoExitEnabled = sender.isOn;
    [self.config saveAutoExitPreference];
}

// MARK: - UITableView DataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.testCases.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    BenchmarkTestCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TestCell" forIndexPath:indexPath];
    cell.delegate = self;
    [cell configureWithTestCase:self.testCases[indexPath.row]];
    return cell;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return @"🧪 测试用例";
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    BenchmarkTestCase *testCase = self.testCases[indexPath.row];
    [self handleRunForTestCase:testCase];
}

- (void)benchmarkTestCellDidTapConfig:(BenchmarkTestCase *)testCase {
    if (self.isRunningAllTests) {
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"批量执行中"
                                                                       message:@"全部执行正在进行，暂时无法修改配置。"
                                                                preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil]];
        [self presentViewController:alert animated:YES completion:nil];
        return;
    }

    NSInteger row = [self.testCases indexOfObject:testCase];
    NSIndexPath *indexPath = row != NSNotFound ? [NSIndexPath indexPathForRow:row inSection:0] : nil;
    [self presentConfigForTestCase:testCase shouldRunAfter:NO indexPath:indexPath];
}

- (void)presentConfigForTestCase:(BenchmarkTestCase *)testCase shouldRunAfter:(BOOL)shouldRunAfter indexPath:(NSIndexPath * _Nullable)indexPath {
    BenchmarkTestConfigViewController *configVC = [[BenchmarkTestConfigViewController alloc] initWithTestCase:testCase];
    configVC.confirmButtonTitle = shouldRunAfter ? @"运行" : @"保存";
    __weak typeof(self) weakSelf = self;
    configVC.onCancel = ^{
        [weakSelf dismissViewControllerAnimated:YES completion:nil];
    };
    configVC.onConfirm = ^(BenchmarkTestCase *updatedCase) {
        [updatedCase persistCustomParams];
        NSInteger row = [weakSelf.testCases indexOfObject:updatedCase];
        if (row != NSNotFound) {
            NSIndexPath *target = [NSIndexPath indexPathForRow:row inSection:0];
            [weakSelf.tableView reloadRowsAtIndexPaths:@[target] withRowAnimation:UITableViewRowAnimationAutomatic];
        } else {
            [weakSelf.tableView reloadData];
        }
        [weakSelf dismissViewControllerAnimated:YES completion:^{
            if (!weakSelf) { return; }
            if (shouldRunAfter) {
                if (updatedCase.type == BenchmarkTestCaseTypePlayback) {
                    [weakSelf runTestCase:updatedCase showModal:YES completion:nil];
                } else {
                    [weakSelf handleRunForTestCase:updatedCase];
                }
            }
        }];
    };

    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:configVC];
    nav.modalPresentationStyle = UIModalPresentationPageSheet;
    if (@available(iOS 15.0, *)) {
        UISheetPresentationController *sheet = nav.sheetPresentationController;
        if (sheet) {
            sheet.detents = @[UISheetPresentationControllerDetent.mediumDetent, UISheetPresentationControllerDetent.largeDetent];
            sheet.prefersGrabberVisible = YES;
        }
    } else {
        nav.modalPresentationStyle = UIModalPresentationFormSheet;
    }

    [self presentViewController:nav animated:YES completion:nil];
}

- (void)handleRunForTestCase:(BenchmarkTestCase *)testCase {
    if (self.isRunningAllTests) {
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"正在执行全部用例"
                                                                       message:@"请等待全部测试执行完毕后再单独运行。"
                                                                preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleDefault handler:nil]];
        [self presentViewController:alert animated:YES completion:nil];
        return;
    }

    if (testCase.type == BenchmarkTestCaseTypePlayback) {
        NSInteger row = [self.testCases indexOfObject:testCase];
        NSIndexPath *rowPath = row != NSNotFound ? [NSIndexPath indexPathForRow:row inSection:0] : nil;
        [self presentConfigForTestCase:testCase shouldRunAfter:YES indexPath:rowPath];
        return;
    }

    if (testCase.type == BenchmarkTestCaseTypeFibonacci) {
        NSInteger depth = [testCase.customParams[kParamFibDepth] integerValue];
        if (depth > 10) {
            NSInteger taskCount = (NSInteger)(pow(2, depth) - 1);
            NSString *warningMsg = [NSString stringWithFormat:@"⚠️ 警告\n\n当前递归深度: %ld\n将产生 %ld 个任务\n\n深度过大会导致执行时间很长！\n\n是否继续执行？",
                                    (long)depth,
                                    (long)taskCount];

            UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"递归深度警告"
                                                                           message:warningMsg
                                                                    preferredStyle:UIAlertControllerStyleAlert];
            __weak typeof(self) weakSelf = self;
            UIAlertAction *continueAction = [UIAlertAction actionWithTitle:@"继续执行"
                                                                     style:UIAlertActionStyleDestructive
                                                                   handler:^(UIAlertAction *action) {
                [weakSelf runTestCase:testCase showModal:YES completion:nil];
            }];
            UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
                                                                   style:UIAlertActionStyleCancel
                                                                 handler:nil];
            [alert addAction:cancelAction];
            [alert addAction:continueAction];
            [self presentViewController:alert animated:YES completion:nil];
            return;
        }
    }

    [self runTestCase:testCase showModal:YES completion:nil];
}

- (void)runAllTestsTapped {
    if (self.isRunningAllTests) {
        return;
    }
    if (self.resultVC.isRunning) {
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"测试进行中"
                                                                       message:@"请等待当前测试完成后再执行全部用例。"
                                                                preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil]];
        [self presentViewController:alert animated:YES completion:nil];
        return;
    }

    if (self.resultVC.presentingViewController) {
        [self.resultVC dismissViewControllerAnimated:NO completion:nil];
        self.resultVC = nil;
    }

    [self cancelCountdownTimer];
    self.pendingAutoExitAfterRunAll = NO;
    self.playbackTestsSkipped = NO;

    NSArray<NSString *> *playbackFiles = [self playbackFileNames];
    NSMutableArray<BenchmarkTestCase *> *queue = [NSMutableArray array];
    BOOL hasPlaybackCase = NO;

    for (BenchmarkTestCase *testCase in self.testCases) {
        if (testCase.type == BenchmarkTestCaseTypePlayback) {
            hasPlaybackCase = YES;
            if (playbackFiles.count == 0) {
                continue;
            }
            for (NSString *fileName in playbackFiles) {
                BenchmarkTestCase *copyCase = [[BenchmarkTestCase alloc] initWithType:testCase.type
                                                                                name:testCase.name
                                                                                icon:testCase.icon];
                copyCase.customParams[kParamSelectedFileName] = fileName;
                [queue addObject:copyCase];
            }
        } else {
            [queue addObject:testCase];
        }
    }

    if (queue.count == 0) {
        if (hasPlaybackCase && playbackFiles.count == 0) {
            self.resultLabel.text = @"⚠️ 未找到任何 playback 文件";
        } else {
            self.resultLabel.text = @"⚠️ 没有可执行的测试";
        }
        [self.activityIndicator stopAnimating];
        self.playbackTestsSkipped = (hasPlaybackCase && playbackFiles.count == 0);
        return;
    }

    if (hasPlaybackCase && playbackFiles.count == 0) {
        self.playbackTestsSkipped = YES;
    }

    self.isRunningAllTests = YES;
    self.runAllQueue = [queue copy];
    self.currentRunAllIndex = 0;
    self.runAllButton.enabled = NO;
    self.resultLabel.text = @"🚀 正在执行全部测试...";
    [self.activityIndicator startAnimating];

    RunAllResultsViewController *resultsVC = [[RunAllResultsViewController alloc] init];
    resultsVC.modalPresentationStyle = UIModalPresentationOverFullScreen;
    resultsVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

    __weak typeof(self) weakSelf = self;
    resultsVC.onClose = ^{
        if (weakSelf.pendingAutoExitAfterRunAll) {
            exit(0);
        }
        weakSelf.runAllResultsVC = nil;
    };
    self.runAllResultsVC = resultsVC;

    [self presentViewController:resultsVC animated:YES completion:^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (!strongSelf) {
            return;
        }
        [resultsVC prepareWithTotalCount:strongSelf.runAllQueue.count];
        if (strongSelf.playbackTestsSkipped) {
            [resultsVC appendLog:@"⚠️ 未找到任何 playback 文件，Playback 测试已跳过。"]; 
        }
        [resultsVC appendLog:@"🚀 开始执行全部测试"];
        [resultsVC updateStatus:@"🚀 正在准备第一个测试..."];
        [strongSelf runNextTestInQueue];
    }];
}

- (void)cancelCountdownTimer {
    if (self.countdownTimer) {
        dispatch_source_cancel(self.countdownTimer);
        self.countdownTimer = nil;
    }
    self.countdownSecondsRemaining = 0;
}

- (void)runNextTestInQueue {
    if (!self.isRunningAllTests) {
        return;
    }

    if (self.currentRunAllIndex >= self.runAllQueue.count) {
        [self finishRunAllSequence];
        return;
    }

    [self cancelCountdownTimer];

    BenchmarkTestCase *testCase = self.runAllQueue[self.currentRunAllIndex];
    self.currentRunAllIndex += 1;

    NSInteger finishedCount = self.currentRunAllIndex;
    NSInteger totalCount = self.runAllQueue.count;
    NSString *progressTag = [NSString stringWithFormat:@"(%ld/%ld)", (long)finishedCount, (long)totalCount];
    NSString *displayName = [self displayNameForTestCase:testCase];
    NSString *startLog = [NSString stringWithFormat:@"▶️ %@ %@ 开始执行", progressTag, displayName];
    if (self.runAllResultsVC) {
        [self.runAllResultsVC appendLog:startLog];
        [self.runAllResultsVC updateStatus:startLog];
    }

    self.resultLabel.text = [NSString stringWithFormat:@"⏱ 正在运行 %@...", displayName];
    [self.activityIndicator startAnimating];

    __weak typeof(self) weakSelf = self;
    [self runTestCase:testCase showModal:NO completion:^(NSString *finalResult, NSTimeInterval duration) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (!strongSelf || !strongSelf.isRunningAllTests) {
            return;
        }

        NSInteger total = strongSelf.runAllQueue.count;
        NSString *summary = [NSString stringWithFormat:@"✅ (%ld/%ld) %@ 完成 - %.3fs", (long)strongSelf.currentRunAllIndex, (long)total, [strongSelf displayNameForTestCase:testCase], duration];
        if (strongSelf.runAllResultsVC) {
            [strongSelf.runAllResultsVC appendLog:[NSString stringWithFormat:@"%@\n%@", summary, finalResult]];
            [strongSelf.runAllResultsVC updateStatus:summary];
        }

        if (strongSelf.currentRunAllIndex >= total) {
            [strongSelf finishRunAllSequence];
        } else {
            BenchmarkTestCase *nextTest = strongSelf.runAllQueue[strongSelf.currentRunAllIndex];
            [strongSelf startCountdownForNextTest:nextTest];
        }
    }];
}

- (void)startCountdownForNextTest:(BenchmarkTestCase *)nextTest {
    [self cancelCountdownTimer];
    self.countdownSecondsRemaining = 6;

    NSString *name = [self displayNameForTestCase:nextTest];
    if (self.runAllResultsVC) {
        NSString *log = [NSString stringWithFormat:@"😴 即将执行 %@，等待 %ld 秒...", name, (long)self.countdownSecondsRemaining];
        [self.runAllResultsVC appendLog:log];
        [self.runAllResultsVC updateCountdown:self.countdownSecondsRemaining nextTestName:name];
    }

    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    self.countdownTimer = timer;

    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
    __weak typeof(self) weakSelf = self;
    dispatch_source_set_event_handler(timer, ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (!strongSelf) {
            return;
        }
        if (!strongSelf.isRunningAllTests) {
            [strongSelf cancelCountdownTimer];
            return;
        }

        strongSelf.countdownSecondsRemaining -= 1;
        if (strongSelf.countdownSecondsRemaining <= 0) {
            [strongSelf cancelCountdownTimer];
            if (strongSelf.runAllResultsVC) {
                [strongSelf.runAllResultsVC updateCountdown:0 nextTestName:[strongSelf displayNameForTestCase:nextTest]];
            }
            [strongSelf runNextTestInQueue];
        } else {
            if (strongSelf.runAllResultsVC) {
                [strongSelf.runAllResultsVC updateCountdown:strongSelf.countdownSecondsRemaining nextTestName:[strongSelf displayNameForTestCase:nextTest]];
            }
        }
    });
    dispatch_resume(timer);
}

- (void)finishRunAllSequence {
    NSUInteger totalExecuted = self.currentRunAllIndex;
    [self cancelCountdownTimer];
    self.isRunningAllTests = NO;
    self.runAllQueue = nil;
    self.currentRunAllIndex = 0;
    self.runAllButton.enabled = YES;
    self.resultLabel.text = @"✅ 全部测试完成";
    [self.activityIndicator stopAnimating];

    BOOL shouldExit = self.config.autoExitEnabled;
    self.pendingAutoExitAfterRunAll = shouldExit;

    NSString *summary = [NSString stringWithFormat:@"✅ 全部 %lu 项执行完毕", (unsigned long)totalExecuted];
    if (self.runAllResultsVC) {
        [self.runAllResultsVC markBatchCompletedWithSummary:summary autoExit:shouldExit];
    } else {
        self.resultLabel.text = summary;
    }

    if (shouldExit) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (self.runAllResultsVC && self.runAllResultsVC.presentingViewController) {
                RunAllResultsViewController *controller = self.runAllResultsVC;
                self.runAllResultsVC = nil;
                [controller dismissViewControllerAnimated:NO completion:^{
                    exit(0);
                }];
            } else if (self.presentedViewController) {
                [self dismissViewControllerAnimated:NO completion:^{
                    exit(0);
                }];
            } else {
                exit(0);
            }
        });
    }
    self.playbackTestsSkipped = NO;
}

// MARK: - 测试执行

- (void)showResult:(NSString *)result {
    dispatch_async(dispatch_get_main_queue(), ^{
        self.resultLabel.text = result;
        [self.activityIndicator stopAnimating];
    });
}

- (void)startTest:(NSString *)testName {
    dispatch_async(dispatch_get_main_queue(), ^{
        self.resultLabel.text = [NSString stringWithFormat:@"正在运行 %@...", testName];
        [self.activityIndicator startAnimating];
    });
}

- (void)runTestCase:(BenchmarkTestCase *)testCase
          showModal:(BOOL)showModal
         completion:(void (^)(NSString *finalResult, NSTimeInterval duration))completion {
    NSDictionary *params = testCase.customParams ?: @{};
    NSString *displayName = [self displayNameForTestCase:testCase];
    NSInteger taskType = IntegerParam(params, kParamTaskType, 0);
    qos_class_t qos = (qos_class_t)IntegerParam(params, kParamQoS, QOS_CLASS_DEFAULT);
    if (qos == 0) {
        qos = QOS_CLASS_DEFAULT;
    }

    void (^completionBlock)(NSString *, NSTimeInterval) = completion ? [completion copy] : nil;

    if (showModal) {
        void (^prepareBlock)(void) = ^{
            if (self.resultVC && self.resultVC.presentingViewController) {
                [self.resultVC loadViewIfNeeded];
                [self.resultVC prepareForTestWithName:displayName icon:testCase.icon];
            } else {
                self.resultVC = [[TestResultViewController alloc] init];
                self.resultVC.modalPresentationStyle = UIModalPresentationOverFullScreen;
                self.resultVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
                [self presentViewController:self.resultVC animated:YES completion:nil];
                [self.resultVC loadViewIfNeeded];
                [self.resultVC prepareForTestWithName:displayName icon:testCase.icon];
            }
        };

        if ([NSThread isMainThread]) {
            prepareBlock();
        } else {
            dispatch_sync(dispatch_get_main_queue(), prepareBlock);
        }
    }

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
        NSDate *startTime = [NSDate date];
        NSMutableString *detailInfo = [NSMutableString string];
        [detailInfo appendString:@"📊 测试配置\n"];
        [detailInfo appendString:@"━━━━━━━━━━━━━━━━━━━━\n"];

        NSInteger totalTasksForAverage = 0;

        switch (testCase.type) {
            case BenchmarkTestCaseTypeForkJoin: {
                NSInteger taskCount = MAX(1, IntegerParam(params, kParamTaskCount, 512));
                NSInteger duration = MAX(1, IntegerParam(params, kParamTaskDuration, 100));
                [detailInfo appendFormat:@"任务类型: %@\n", DisplayTaskType(taskType)];
                [detailInfo appendFormat:@"任务数量: %ld\n", (long)taskCount];
                [detailInfo appendFormat:@"任务时长: %@\n", FormatMicrosecondsValue(duration)];
                [detailInfo appendFormat:@"任务 QoS: %@\n\n", DisplayQoS(qos)];
                totalTasksForAverage = taskCount;
                break;
            }
            case BenchmarkTestCaseTypeFibonacci: {
                NSInteger depth = MAX(1, IntegerParam(params, kParamFibDepth, 10));
                NSInteger duration = MAX(1, IntegerParam(params, kParamTaskDuration, 100));
                [detailInfo appendFormat:@"任务类型: %@\n", DisplayTaskType(taskType)];
                [detailInfo appendFormat:@"递归深度: %ld\n", (long)depth];
                [detailInfo appendFormat:@"任务时长: %@\n", FormatMicrosecondsValue(duration)];
                [detailInfo appendFormat:@"任务 QoS: %@\n\n", DisplayQoS(qos)];
                totalTasksForAverage = (NSInteger)(pow(2, depth) - 1);
                break;
            }
            case BenchmarkTestCaseTypeAriawNSOperation:
            case BenchmarkTestCaseTypeAriawSemaphore: {
                NSInteger bufferCount = MAX(1, IntegerParam(params, kParamBufferCount, 4));
                NSInteger sliceCount = MAX(1, IntegerParam(params, kParamSliceCount, 512));
                NSInteger duration = MAX(1, IntegerParam(params, kParamTaskDuration, 200));
                [detailInfo appendFormat:@"任务类型: %@\n", DisplayTaskType(taskType)];
                [detailInfo appendFormat:@"缓冲区: %ld\n", (long)bufferCount];
                [detailInfo appendFormat:@"Slice 数量: %ld\n", (long)sliceCount];
                [detailInfo appendFormat:@"任务时长: %@\n", FormatMicrosecondsValue(duration)];
                [detailInfo appendFormat:@"任务 QoS: %@\n\n", DisplayQoS(qos)];
                totalTasksForAverage = sliceCount * 3;
                break;
            }
            case BenchmarkTestCaseTypeSerialQueue: {
                NSInteger taskCount = MAX(1, IntegerParam(params, kParamTaskCount, 512));
                NSInteger duration = MAX(1, IntegerParam(params, kParamTaskDuration, 10));
                NSInteger interval = MAX(0, IntegerParam(params, kParamSubmitInterval, 100));
                [detailInfo appendFormat:@"任务类型: %@\n", DisplayTaskType(taskType)];
                [detailInfo appendFormat:@"任务数量: %ld\n", (long)taskCount];
                [detailInfo appendFormat:@"任务时长: %@\n", FormatMicrosecondsValue(duration)];
                [detailInfo appendFormat:@"提交间隔: %@\n", FormatMicrosecondsValue(interval)];
                [detailInfo appendFormat:@"任务 QoS: %@\n\n", DisplayQoS(qos)];
                totalTasksForAverage = taskCount;
                break;
            }
            case BenchmarkTestCaseTypeConcurrentQueue: {
                NSInteger taskCount = MAX(1, IntegerParam(params, kParamTaskCount, 512));
                NSInteger duration = MAX(1, IntegerParam(params, kParamTaskDuration, 1000));
                NSInteger interval = MAX(0, IntegerParam(params, kParamSubmitInterval, 100));
                NSInteger concurrency = MAX(1, IntegerParam(params, kParamMaxConcurrency, 4));
                [detailInfo appendFormat:@"任务类型: %@\n", DisplayTaskType(taskType)];
                [detailInfo appendFormat:@"任务数量: %ld\n", (long)taskCount];
                [detailInfo appendFormat:@"任务时长: %@\n", FormatMicrosecondsValue(duration)];
                [detailInfo appendFormat:@"最大并发度: %ld\n", (long)concurrency];
                [detailInfo appendFormat:@"提交间隔: %@\n", FormatMicrosecondsValue(interval)];
                [detailInfo appendFormat:@"任务 QoS: %@\n\n", DisplayQoS(qos)];
                totalTasksForAverage = taskCount;
                break;
            }
            case BenchmarkTestCaseTypePeriodicTasks: {
                NSInteger taskType = MAX(0, IntegerParam(params, kParamTaskType, 0));
                NSInteger count = MAX(1, IntegerParam(params, kParamTaskCount, 100));  // Now serves as cnt
                NSInteger duration = MAX(1, IntegerParam(params, kParamTaskDuration, 100));  // cost in microseconds
                [detailInfo appendFormat:@"任务类型: %@\n", DisplayTaskType(taskType)];
                [detailInfo appendFormat:@"任务数量: %ld\n", (long)count];  // Updated: task count instead of run count
                [detailInfo appendFormat:@"任务时长: %@\n", FormatMicrosecondsValue(duration)];  // cost
                [detailInfo appendFormat:@"任务 QoS: %@\n\n", DisplayQoS(qos)];
                totalTasksForAverage = count;  // Updated: use task count as total tasks
                break;
            }
            case BenchmarkTestCaseTypePlayback: {
                NSString *fileName = params[kParamSelectedFileName];
                [detailInfo appendFormat:@"Playback 文件: %@\n\n", fileName ?: @"未选择"];
                totalTasksForAverage = 0;
                break;
            }
        }

        [detailInfo appendString:@"⏱ 执行中...\n"];
        [detailInfo appendString:@"━━━━━━━━━━━━━━━━━━━━\n"];

        if (showModal) {
            [self.resultVC updateProgress:detailInfo];
        }

        NSLog(@"[DEBUG] 开始执行测试: %@, 参数: %@", displayName, params);

        switch (testCase.type) {
            case BenchmarkTestCaseTypeForkJoin:
                [self executeForkJoinTest:testCase];
                break;
            case BenchmarkTestCaseTypeFibonacci:
                [self executeFibonacciTest:testCase];
                break;
            case BenchmarkTestCaseTypeAriawNSOperation:
                [self executeAriawNSOperationTest:testCase];
                break;
            case BenchmarkTestCaseTypeAriawSemaphore:
                [self executeAriawSemaphoreTest:testCase];
                break;
            case BenchmarkTestCaseTypeSerialQueue:
                [self executeSerialQueueTest:testCase];
                break;
            case BenchmarkTestCaseTypeConcurrentQueue:
                [self executeConcurrentQueueTest:testCase];
                break;
            case BenchmarkTestCaseTypePeriodicTasks:
                [self executePeriodicTasksTest:testCase];
                break;
            case BenchmarkTestCaseTypePlayback:
                [self executePlaybackTest:testCase];
                break;
        }

        NSLog(@"[DEBUG] 测试执行完成: %@", testCase.name);
        NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:startTime];

        NSMutableString *finalResult = [NSMutableString stringWithString:detailInfo];
        [finalResult appendString:@"\n✅ 测试完成\n"];
        [finalResult appendString:@"━━━━━━━━━━━━━━━━━━━━\n"];
        [finalResult appendFormat:@"总耗时: %.3f 秒\n", elapsed];

        if (testCase.type == BenchmarkTestCaseTypeFibonacci) {
            NSInteger depth = MAX(1, IntegerParam(params, kParamFibDepth, 10));
            NSInteger actualTaskCount = (NSInteger)(pow(2, depth) - 1);
            [finalResult appendFormat:@"递归深度: %ld\n", (long)depth];
            [finalResult appendFormat:@"实际任务数: %ld (2^%ld - 1)\n", (long)actualTaskCount, (long)depth];
            [finalResult appendFormat:@"平均每任务: %.3f ms\n", (elapsed * 1000.0) / MAX(actualTaskCount, 1)];
        } else if (totalTasksForAverage > 0) {
            [finalResult appendFormat:@"平均每任务: %.3f ms\n", (elapsed * 1000.0) / totalTasksForAverage];
        }

        if (showModal) {
            [self.resultVC showResult:finalResult duration:elapsed];
        }
        [self showResult:[NSString stringWithFormat:@"%@ %@ 完成 - %.3fs", testCase.icon, displayName, elapsed]];

        if (completionBlock) {
            dispatch_async(dispatch_get_main_queue(), ^{
                completionBlock([finalResult copy], elapsed);
            });
        }

        if (self.config.autoExitEnabled && !self.isRunningAllTests) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (showModal && self.resultVC && self.resultVC.presentingViewController) {
                    UIViewController *controller = self.resultVC;
                    self.resultVC = nil;
                    [controller dismissViewControllerAnimated:NO completion:^{
                        exit(0);
                    }];
                } else if (self.presentedViewController) {
                    [self dismissViewControllerAnimated:NO completion:^{
                        exit(0);
                    }];
                } else {
                    exit(0);
                }
            });
        }
    });
}

- (void)executeForkJoinTest:(BenchmarkTestCase *)testCase {
    NSDictionary *params = testCase.customParams ?: @{};
    size_t taskType = (size_t)MAX(0, IntegerParam(params, kParamTaskType, 0));
    size_t taskCount = (size_t)MAX(1, IntegerParam(params, kParamTaskCount, 512));
    size_t duration = (size_t)MAX(1, IntegerParam(params, kParamTaskDuration, 100));
    qos_class_t qos = (qos_class_t)IntegerParam(params, kParamQoS, QOS_CLASS_DEFAULT);
    if (qos == 0) {
        qos = QOS_CLASS_UNSPECIFIED;
    }
    execute_fork_join_test(taskType, taskCount, duration, qos);
}

- (void)executeFibonacciTest:(BenchmarkTestCase *)testCase {
    NSDictionary *params = testCase.customParams ?: @{};
    size_t taskType = (size_t)MAX(0, IntegerParam(params, kParamTaskType, 0));
    size_t depth = (size_t)MAX(1, IntegerParam(params, kParamFibDepth, 10));
    size_t duration = (size_t)MAX(1, IntegerParam(params, kParamTaskDuration, 100));
    qos_class_t qos = (qos_class_t)IntegerParam(params, kParamQoS, QOS_CLASS_DEFAULT);
    if (qos == 0) {
        qos = QOS_CLASS_UNSPECIFIED;
    }
    execute_fibonacci_test(taskType, depth, duration, qos);
}

- (void)executeAriawNSOperationTest:(BenchmarkTestCase *)testCase {
    NSDictionary *params = testCase.customParams ?: @{};
    size_t taskType = (size_t)MAX(0, IntegerParam(params, kParamTaskType, 0));
    size_t bufferCount = (size_t)MAX(1, IntegerParam(params, kParamBufferCount, 4));
    size_t sliceCount = (size_t)MAX(1, IntegerParam(params, kParamSliceCount, 512));
    size_t duration = (size_t)MAX(1, IntegerParam(params, kParamTaskDuration, 200));
    qos_class_t qos = (qos_class_t)IntegerParam(params, kParamQoS, QOS_CLASS_DEFAULT);
    if (qos == 0) {
        qos = QOS_CLASS_UNSPECIFIED;
    }
    execute_ariaw_nsoperation_test(taskType, bufferCount, sliceCount, duration, qos);
}

- (void)executeAriawSemaphoreTest:(BenchmarkTestCase *)testCase {
    NSDictionary *params = testCase.customParams ?: @{};
    size_t taskType = (size_t)MAX(0, IntegerParam(params, kParamTaskType, 0));
    size_t bufferCount = (size_t)MAX(1, IntegerParam(params, kParamBufferCount, 4));
    size_t sliceCount = (size_t)MAX(1, IntegerParam(params, kParamSliceCount, 512));
    size_t duration = (size_t)MAX(1, IntegerParam(params, kParamTaskDuration, 200));
    qos_class_t qos = (qos_class_t)IntegerParam(params, kParamQoS, QOS_CLASS_DEFAULT);
    if (qos == 0) {
        qos = QOS_CLASS_UNSPECIFIED;
    }
    execute_ariaw_semaphore_test(taskType, bufferCount, sliceCount, duration, qos);
}

- (void)executeSerialQueueTest:(BenchmarkTestCase *)testCase {
    NSDictionary *params = testCase.customParams ?: @{};
    size_t taskType = (size_t)MAX(0, IntegerParam(params, kParamTaskType, 0));
    size_t taskCount = (size_t)MAX(1, IntegerParam(params, kParamTaskCount, 512));
    size_t duration = (size_t)MAX(1, IntegerParam(params, kParamTaskDuration, 10));
    size_t submitInterval = (size_t)MAX(0, IntegerParam(params, kParamSubmitInterval, 100));
    qos_class_t qos = (qos_class_t)IntegerParam(params, kParamQoS, QOS_CLASS_DEFAULT);
    if (qos == 0) {
        qos = QOS_CLASS_UNSPECIFIED;
    }
    execute_serial_queue_test(taskType, taskCount, duration, submitInterval, qos);
}

- (void)executeConcurrentQueueTest:(BenchmarkTestCase *)testCase {
    NSDictionary *params = testCase.customParams ?: @{};
    size_t taskType = (size_t)MAX(0, IntegerParam(params, kParamTaskType, 0));
    size_t taskCount = (size_t)MAX(1, IntegerParam(params, kParamTaskCount, 512));
    size_t duration = (size_t)MAX(1, IntegerParam(params, kParamTaskDuration, 1000));
    int maxConcurrency = (int)MAX(1, IntegerParam(params, kParamMaxConcurrency, 4));
    size_t submitInterval = (size_t)MAX(0, IntegerParam(params, kParamSubmitInterval, 100));
    qos_class_t qos = (qos_class_t)IntegerParam(params, kParamQoS, QOS_CLASS_DEFAULT);
    if (qos == 0) {
        qos = QOS_CLASS_UNSPECIFIED;
    }
    execute_concurrent_queue_test(taskType, taskCount, duration, maxConcurrency, submitInterval, qos);
}

- (void)executePeriodicTasksTest:(BenchmarkTestCase *)testCase {
    NSDictionary *params = testCase.customParams ?: @{};
    size_t taskType = (size_t)MAX(0, IntegerParam(params, kParamTaskType, 0));
    size_t count = (size_t)MAX(1, IntegerParam(params, kParamTaskCount, 100));  // Now serves as cnt
    size_t duration = (size_t)MAX(1, IntegerParam(params, kParamTaskDuration, 100));  // cost in microseconds
    qos_class_t qos = (qos_class_t)IntegerParam(params, kParamQoS, QOS_CLASS_DEFAULT);
    if (qos == 0) {
        qos = QOS_CLASS_UNSPECIFIED;
    }
    // Updated function call for new parameter format: task_type, cnt, cost, qos
    execute_periodic_tasks_test(taskType, count, duration, qos);
}

- (void)executePlaybackTest:(BenchmarkTestCase *)testCase {
    NSString *fileName = testCase.customParams[kParamSelectedFileName];
    if (!fileName || fileName.length == 0) {
        NSLog(@"[ERROR] Playback file not selected");
        return;
    }

    NSString *baseName = [fileName stringByDeletingPathExtension];
    NSString *extension = [fileName pathExtension];
    if (extension.length == 0) {
        extension = @"playback";
    }

    NSString *filePath = [[NSBundle mainBundle] pathForResource:baseName ofType:extension];
    if (!filePath) {
        NSArray<NSString *> *allResources = [[NSBundle mainBundle] pathsForResourcesOfType:@"playback" inDirectory:nil];
        for (NSString *candidate in allResources) {
            if ([[candidate lastPathComponent] isEqualToString:fileName]) {
                filePath = candidate;
                break;
            }
        }
    }

    if (!filePath) {
        NSLog(@"[ERROR] Playback file %@ not found in bundle", fileName);
        return;
    }

    NSLog(@"[DEBUG] Running playback from file: %@", filePath);
    run_playback([filePath UTF8String], 0);
}

@end
